<template>
  <div :style="style"></div>
</template>

<script>
import * as monaco from "monaco-editor";
var debounce = require("lodash/debounce");
import nginx from "../lib/nginx";
import completion from "../lib/completion";

module.exports = {
  props: {
    width: { type: [String, Number], default: "100%" },
    height: { type: [String, Number], default: "100%" },
    code: { type: String, default: "// code \n" },
    srcPath: { type: String },
    language: { type: String, default: "javascript" },
    theme: { type: String, default: "vs-dark" }, // vs, hc-black
    options: { type: Object, default: () => {} },
    highlighted: {
      type: Array,
      default: () => [
        {
          number: 0,
          class: ""
        }
      ]
    },
    changeThrottle: { type: Number, default: 0 }
  },
  mounted() {
    this.createMonaco();
  },
  destroyed() {
    this.destroyMonaco();
  },
  computed: {
    style() {
      const { width, height } = this;
      const fixedWidth =
        width.toString().indexOf("%") !== -1 ? width : `${width}px`;
      const fixedHeight =
        height.toString().indexOf("%") !== -1 ? height : `${height}px`;
      return {
        width: fixedWidth,
        height: fixedHeight
      };
    },
    editorOptions() {
      return Object.assign({}, this.defaults, this.options, {
        value: this.code,
        language: this.language,
        theme: this.theme
      });
    }
  },
  data() {
    return {
      defaults: {
        selectOnLineNumbers: true,
        roundedSelection: false,
        readOnly: false,
        cursorStyle: "line",
        automaticLayout: false,
        glyphMargin: true
      }
    };
  },
  watch: {
    highlighted: {
      handler(lines) {
        this.highlightLines(lines);
      },
      deep: true
    }
  },
  updated() {
    this.code;
    debugger;
  },
  methods: {
    highlightLines(lines) {
      if (!this.editor) {
        return;
      }
      lines.forEach(line => {
        const className = line.class;
        const highlighted = this.$el.querySelector(`.${className}`);

        if (highlighted) {
          highlighted.classList.remove(className);
        }

        const number = parseInt(line.number);
        if ((!this.editor && number < 1) || isNaN(number)) {
          return;
        }

        const selectedLine = this.$el.querySelector(
          `.view-lines [linenumber="${number}"]`
        );
        if (selectedLine) {
          selectedLine.classList.add(className);
        }
      });
    },
    editorHasLoaded(editor, monaco) {
      this.editor = editor;
      this.monaco = monaco;
      this.editor.onDidChangeModelContent(event =>
        this.codeChangeHandler(editor, event)
      );
      this.$emit("mounted", editor);
    },
    codeChangeHandler: function(editor) {
      if (this.codeChangeEmitter) {
        this.codeChangeEmitter(editor);
      } else {
        this.codeChangeEmitter = debounce(function(editor) {
          this.$emit("codeChange", editor);
        }, this.changeThrottle);
        this.codeChangeEmitter(editor);
      }
    },
    createMonaco() {
      // debugger;
      // 注册自定义语言
      monaco.languages.register({ id: "nginx" });
      // 为该自定义语言基本的Token
      monaco.languages.setMonarchTokensProvider("nginx", nginx);
      // 为该语言注册一个语言提示器--联想
      monaco.languages.registerCompletionItemProvider("nginx", {
        provideCompletionItems: () => {
          return { suggestions: completion };
        }
      });
      monaco.languages.setLanguageConfiguration('nginx', {
         comments: {
            lineComment: "#"
        },
        brackets: [["{", "}"], ["[", "]"], ["(", ")"]],
        autoClosingPairs: [{
            open: "{",
            close: "}"
        }, {
            open: "[",
            close: "]"
        }, {
            open: "(",
            close: ")"
        }, {
            open: '"',
            close: '"'
        }, {
            open: "'",
            close: "'"
        }],
        surroundingPairs: [{
            open: "{",
            close: "}"
        }, {
            open: "[",
            close: "]"
        }, {
            open: "(",
            close: ")"
        }, {
            open: '"',
            close: '"'
        }, {
            open: "'",
            close: "'"
        }],
        folding: {
            offSide: !0
        }
      })

      this.editor = monaco.editor.create(this.$el, this.editorOptions);
      this.editorHasLoaded(this.editor, window.monaco);
    },
    destroyMonaco() {
      if (typeof this.editor !== "undefined") {
        this.editor.dispose();
      }
    }
  }
};
</script>
